﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Idlesoft.Utils;
using System.Collections;
namespace Idlesoft.Utils
{
	public static class EnumerableExtensions
	{
		public static IEnumerable<TItem> Plus<TItem>(this IEnumerable<TItem> lhs, IEnumerable<TItem> rhs)
		{
			List<TItem> list = new List<TItem>();
			list.AddRange(lhs);
			list.AddRange(rhs);
			return list.ToArray();
		}
		public static TItem[] Plus<TItem>(this TItem[] lhs, params TItem[] rhs)
		{
			TItem[] plus = null;
			if (lhs != null || rhs != null)
			{
				List<TItem> list = new List<TItem>();
				if (lhs != null)
					list.AddRange(lhs);
				if (rhs != null)
					list.AddRange(rhs);
				plus = list.ToArray();
			}
			return plus;
		}
		public static List<TItem> Plus<TItem>(this List<TItem> lhs, List<TItem> rhs)
		{
			List<TItem> list = new List<TItem>(lhs.ToArray());
			list.AddRange(rhs.ToArray());
			return list;
		}

		#region head
		public static string Head(this string s)
		{
			return !s.IsNullOrEmpty() ? s.ToCharArray().Head().ToString() : null;
		}
		public static string Head(this string s, int count)
		{
			return !s.IsNullOrEmpty() ? s.ToCharArray().Head(count).ToString() : null;
		}
		public static TItem Head<TItem>(this IEnumerable<TItem> items)
		{
			return items.FirstOrDefault();
		}
		public static IEnumerable<TItem> Head<TItem>(this IEnumerable<TItem> items, int count)
		{
			return !items.IsNullOrEmpty() ? items.Take(count) : null;
		}
		public static TItem[] Head<TItem>(this TItem[] items, int count)
		{
			return Head(items.AsEnumerable(), count).ToArray();
		}
		public static List<TItem> Head<TItem>(this List<TItem> items, int count)
		{
			return Head(items.AsEnumerable(), count).ToList();
		}
		#endregion head

		#region last
		public static string Last(this string s)
		{
			return !s.IsNullOrEmpty() ? s.ToCharArray().Last().ToString() : null;
		}
		public static string Last(this string s, int count)
		{
			return !s.IsNullOrEmpty() ? s.ToCharArray().Last(count).ToString() : null;
		}
		public static IEnumerable<TItem> Last<TItem>(this IEnumerable<TItem> items, int count)
		{
			return !items.IsNullOrEmpty() ? items.Skip(items.Count() - count).Take(count) : null;
		}
		public static TItem[] Last<TItem>(this TItem[] items, int count)
		{
			return Last(items.AsEnumerable(), count).ToArray();
		}
		public static List<TItem> Last<TItem>(this List<TItem> items, int count)
		{
			return Last(items.AsEnumerable(), count).ToList();
		}
		#endregion last

		#region tail
		public static string Tail(this string s)
		{
			return !s.IsNullOrEmpty() ? new string(s.ToCharArray().Tail().ToArray()) : null;
		}
		public static IEnumerable<TItem> Tail<TItem>(this IEnumerable<TItem> items)
		{
			return !items.IsNullOrEmpty() ? items.Skip(1).Take(items.Count() - 1) : null;
		}
		public static TItem[] Tail<TItem>(this TItem[] items)
		{
			return Tail(items.AsEnumerable()).ToArray();
		}
		public static List<TItem> Tail<TItem>(this List<TItem> items)
		{
			return Tail(items.AsEnumerable()).ToList();
		}
		#endregion tail

		#region folds
		public static TAcc Fold<TAcc, TItem>(this IEnumerable<TItem> items, Func<TAcc, TItem, TAcc> func, TAcc acc)
		{
			foreach (var item in items)
				acc = func(acc, item);
			return acc;
		}
		public static TAcc FoldLeft<TAcc, TItem>(this IList<TItem> items, Func<TAcc, TItem, TAcc> func, TAcc acc)
		{
			for (int index = 0; index < items.Count; ++index)
				acc = func(acc, items[index]);
			return acc;
		}
		public static TAcc FoldRight<TAcc, TItem>(this IList<TItem> items, Func<TAcc, TItem, TAcc> func, TAcc acc)
		{
			for (int index = items.Count - 1; index >= 0; ++index)
				acc = func(acc, items[index]);
			return acc;
		}
		#endregion folds

		#region surround
		public static string Surround<TItem>(this TItem item, object before, object after)
		{
			return string.Format("{0}{1}{2}",
				before != null ? before : "",
				item != null ? item.ToString() : "",
				after != null ? after : "");
		}
		#endregion surround

		#region between
		public static string Between<TItem>(this IEnumerable<TItem> items)
		{
			return Between<TItem>(items, " ");
		}
		public static string Between<TItem>(this IEnumerable<TItem> items, object between)
		{
			string betweened = null;
			if (!items.IsNullOrEmpty())
			{
				betweened = items.Head().ToString();
				if (between != null)
					items.Tail().ForEach(item => betweened += between.ToString() + item.ToString());
				else
					items.Tail().ForEach(item => betweened += item.ToString());
			}
			return betweened;
		}

		#endregion between

		#region flatten
		public static string Flatten<TItem>(this IEnumerable<TItem> items)
		{
			return Flatten<TItem>(items, " ");
		}
		public static string Flatten<TItem>(this IEnumerable<TItem> items, object between)
		{
			return Flatten<TItem>(items, null, between, null);
		}
		public static string Flatten<TItem>(this IEnumerable<TItem> items, object before, object between, object after)
		{
			return items.Between(between).Surround(before, after);
		}
		#endregion flatten

		#region ienumerable foreach
		public static void ForEach<TItem>(this IEnumerable items, Action<TItem> action)
		{
			foreach (var o in items)
				action( (TItem)o );
		}
		public static void ForEach<TItem>(this IEnumerable<TItem> items, Action<TItem> action)
		{
			foreach (var item in items)
				action(item);
		}
		#endregion ienumerable foreach
	}
}
